#include "http_servlet.h"
#include <assert.h>
#include "File.h"
#include "pfunc_str.h"
#include "pfunc_time.h"

#include "business_def.h"
#include "svc_control.h"
#include "pfunc_format.h"
#include "pfunc_print.h"
#ifdef WIN32
#include "strchange.h"
#endif

http_servlet::http_servlet(acl::socket_stream* stream, acl::session* session)
	: acl::HttpServlet(stream, session)
{
	BusinessDef* ptr_BD = BusinessDef::getInstance();
	ptr_BD->getSvcInfo(svcTriples);
	std::map<int, SvcDesc>::iterator it = svcTriples.begin();
	for(;it!=svcTriples.end();++it)
	{
		char buf_dir[128]={0};
		#ifdef WIN32
		sprintf(buf_dir,"%s\\var",it->second.app_dir.c_str());
		#else
		sprintf(buf_dir,"%s/var",it->second.app_dir.c_str());
		#endif // WIN32	
		std::string var_dir = std::string(buf_dir);
		pyfree::createDir(var_dir);
	}
}

http_servlet::~http_servlet(void)
{

}

bool http_servlet::doError(acl::HttpServletRequest&, acl::HttpServletResponse&)
{
	return false;
}

bool http_servlet::doUnknown(acl::HttpServletRequest&,
	acl::HttpServletResponse& res)
{
	res.setStatus(400);
	res.setContentType("text/html; charset=");
	// 发送 http 响应头
	if (res.sendHeader() == false)
		return false;
	// 发送 http 响应体
	acl::string buf("<root error='unkown request method' />\r\n");
	(void) res.getOutputStream().write(buf);
	return false;
}

bool http_servlet::doGet(acl::HttpServletRequest& req,
	acl::HttpServletResponse& res)
{
	return doPost(req, res);
}

bool http_servlet::doPost(acl::HttpServletRequest& req,
	acl::HttpServletResponse& res)
{
	bool keep_alive = req.isKeepAlive();

	res.setContentType("text/html")		// 设置响应字符集
		.setCharacterEncoding("utf-8");
		// .setKeepAlive(keep_alive)		// 设置是否保持长连接
		// .setChunkedTransferEncoding(true);	// chunked 传输模式
	Print_NOTICE("keep_alive:%d\n",(int)keep_alive);
	// 发送 http 响应体
	// 创建 HTTP 响应头
	// res.addCookie("name1", "value1");
	// res.addCookie("name2", "value2", ".test.com", "/", 3600 * 24);
	// res.setStatus(400);  // 可以设置返回的状态码

	// 获得 HTTP 请求的数据类型，正常的参数类型，即 name&value 方式
	// 还是 MIME 数据类型，还是数据流类型
	acl::http_request_t request_type = req.getRequestType();
	Print_NOTICE("request_type:%d\n",(int)request_type);
	if (request_type == acl::HTTP_REQUEST_NORMAL)
		return doParams(req, res);
	else if (request_type == acl::HTTP_REQUEST_MULTIPART_FORM)
		return doForms(req, res);
	assert(request_type == acl::HTTP_REQUEST_OCTET_STREAM);
	return doOctetStream(req, res);
}

// POST 方式且满足：
// Content-Type: application/octet-stream
bool http_servlet::doOctetStream(acl::HttpServletRequest&, acl::HttpServletResponse&)
{
	return false;
}

// GET 方式或 POST 方式且满足：
// Content-Type: application/x-www-form-urlencoded
bool http_servlet::doParams(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
	const char* RequestUri_ = req.getRequestUri();
	if(NULL!=RequestUri_)
	{
		Print_NOTICE("RequestUri_:%s\n",RequestUri_);
	}
	const char* parms = req.getQueryString();
	if(NULL!=parms&&NULL!=RequestUri_)
	{
		Print_NOTICE("parms:%s\n",parms);
		if (pyfree::containStr_start(std::string(RequestUri_),"/file_download?"))
		{
			// std::vector<std::string> div_list;
			// pyfree::string_divide(div_list,std::string(RequestUri_),"?");
			// if(div_list.size()==2&&div_list.at(0).size()>1)
			// {
			// 获得输入流
			// printf("div_list[0]=%s\n",div_list.at(0).c_str());
			// const char* filepath = "./gather/gather.xml";
			// std::string file_ = div_list.at(0).substr(1);
			std::string file_ = std::string(parms);
			// printf("filepath=%s\n",file_.c_str());
			file_ = pyfree::UrlDecode(file_);
			// printf("filepath=%s\n",file_.c_str());
			acl::ifstream in;
			in.open_read(file_.c_str());

			// 获得输出流
			acl::ostream& out = res.getOutputStream();

			long long int len = in.fsize();
			res.setContentType("application/octet-stream"); 
			res.setHeader("Content-Disposition","attachment"); 
			res.setContentLength(len);
			if(len>0){
				Print_NOTICE("%s size:%lld\n",file_.c_str(),len);
				char  buf[4096];
				int   ret;
				// 写入HTTP客户端响应数据
				while ((ret = in.read(buf, 4096, false))>0)
				{
					out.write(buf, ret);
				}
				out.fflush();
			}
			in.close();
			res.setRange(0,len,len);
			return true;
			// }
		}
	}

	return doResponse(req, res);
}

bool http_servlet::doForms(acl::HttpServletRequest& req
    , acl::HttpServletResponse& res)
{
	const char* RequestUri_ = req.getRequestUri();
	if(NULL!=RequestUri_)
	{
		Print_NOTICE("RequestUri_:%s\n",RequestUri_);
		if (pyfree::containStr_start(std::string(RequestUri_),"/svc_control"))
		{
			return doControl(req, res);
		}
		if (strcmp(RequestUri_, "/file_upload") == 0)
		{
			return doUpload(req,res);
		}
	}

	return false;
};

bool http_servlet::get_SVCFile_XMLDesc(acl::string &xml_desc)
{
	if(svcTriples.empty())
		return false;
	std::map<int, SvcDesc>::iterator it = svcTriples.begin();
	acl::string down_desc = "";
	down_desc+="<table border=\"1\" valign=\"top\" >";
	int index = 0;
	int size = (int)svcTriples.size();
	int column_start_flag = 0;
	int clolumn_size = 3;
	for(;it!=svcTriples.end();++it)
	{
		std::vector<std::string> file_list;
		std::string dir_gather = it->second.app_dir;

		std::vector<std::string> ext_list;
		pyfree::string_divide(ext_list,it->second.conf_ext,";");
		for(unsigned int i=0; i<ext_list.size(); ++i)
		{
			pyfree::getAllFileName_dot(dir_gather,ext_list.at(i),file_list);
		}
		Print_NOTICE("dir:%s,file_list(%s) size:%d\n"
			,dir_gather.c_str()
			,it->second.conf_ext.c_str()
			,(int)file_list.size());
		if(0==(index%clolumn_size))
		{
			down_desc+="<tr>";
			column_start_flag = index;
		}
		char buf_h[256]={0};
		std::string status_ = pyfree::get_svc_status_desc((char*)it->second.svc_name.c_str());
		sprintf(buf_h,"<td valign=\"top\"><h4>%s服务:</h4>"
			"<form style=\"float:left;\" enctype=\"multipart/form-data\" method=POST action=\"svc_control?%d=start\" >"
			"<button type=submit>启动</button>"
			"</form>"
			"<form style=\"float:left;\" enctype=\"multipart/form-data\" method=POST action=\"svc_control?%d=stop\" >"
			"<button type=submit>关闭</button>"
			"</form>"
			"<p><strong>&nbsp;&nbsp;%s</strong></p><br>"
			,it->second.svc_name.c_str()
			,it->first
			,it->first
			,status_.c_str());
		down_desc+=acl::string(buf_h);
		down_desc +="<form enctype=\"multipart/form-data\" method=POST action=\"file_upload\">";
		sprintf(buf_h,"上传文件(%s):<br><input type=file name=\"%s\" value=\"\">"
						"<input type=submit name=\"%s_submit\" value=\"提交\"><br>"
						,it->second.conf_ext.c_str()
						,it->second.app_dir.c_str()
						,it->second.svc_name.c_str());
		down_desc += acl::string(buf_h);
		down_desc += "</form>";
		sprintf(buf_h,"配置文件(%s):<br><ul>"
			,it->second.conf_ext.c_str());
		down_desc+=acl::string(buf_h);
		acl::string file_xml="";
		
		for(unsigned int i = 0; i<file_list.size(); ++i)
		{
			std::string file_name = file_list.at(i);
			std::string file_path="";
			#ifdef WIN32
			file_path = dir_gather+"\\"+file_name;
			#else
			file_path = dir_gather+"/"+file_name;
			#endif
			std::string time_str = pyfree::getDateTime(pyfree::getFileModifyTime(file_path));
			file_path = pyfree::UrlEncode(file_path);
			#ifdef WIN32
			file_name = pyfree::ASCII2UTF_8(file_name);
			#endif
			char buf_xml[512]={0};
			sprintf(buf_xml
			, "<li>%s  <a href=\"file_download?%s\" download=\"%s\">%s</a></li>"
			, time_str.c_str()
			, file_path.c_str()
			, file_name.c_str()
			, file_name.c_str());
			file_xml+=acl::string(buf_xml);
		}
		down_desc+=file_xml;
		down_desc+="</ul></td>";
		if((column_start_flag!=index&&0==(index%clolumn_size))||index==(size-1))
		{
			down_desc+="</tr>";
		}
		index+=1;
	}
	xml_desc+=down_desc;
	xml_desc+="</table>";
	return !xml_desc.empty();
}

void http_servlet::create_html_desc(acl::string &buf)
{
	// 创建 xml 格式的数据体
	char html_buf_h[] = "<html>"
						"<head>"
						"<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\"/>"
						"</head>"
						"<body>";
	char html_buf_b[] = "</body>"
						"</html>";

	acl::string file_xml = "";
	get_SVCFile_XMLDesc(file_xml);
	buf = acl::string(html_buf_h);
	buf+=file_xml;
	buf+=acl::string(html_buf_b);
}

bool http_servlet::doResponse(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
	// 获得浏览器传来的 cookie 值
	// const char* cookie1 = req.getCookieValue("name1");
	// const char* cookie2 = req.getCookieValue("name2");
	// printf("cookie1:%s,cookie2:%s\n",cookie1,cookie2);
	// printf("cookie1:%s\n",cookie1);
	// 获得 sid session 值
// #if 0
// 	const char* sid = req.getSession().getAttribute("sid");
// #else
// 	const char* sid = "test_sid";
// #endif
	
	acl::string buf = "";
	create_html_desc(buf);
	// 发送 http 响应头
	if (res.sendHeader() == false)
	{
		Print_WARN("sendHeader fail!\n");
		return false;
	}
	// 发送 http 响应体
	if (res.getOutputStream().write(buf) == -1)
	{
		Print_WARN("write fail!\n");
		return false;
	}
	// printf(".....3.....\n");
	return true;
}

bool http_servlet::doControl(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
	// printf("svc_control do it\n");
	// const char* param1_ = req.getParameter("name1");
	// if(NULL!=param1_){
	// 	printf("param1_:%s\n",param1_);
	// }
	const char* parms = req.getQueryString();
	if(NULL!=parms){
		Print_NOTICE("parms:%s\n",parms);
		std::vector<std::string> div_list;
		pyfree::string_divide(div_list,std::string(parms),"=");
		if(div_list.size()==2)
		{
			int id_ = atoi(div_list.at(0).c_str());
			std::map<int, SvcDesc>::iterator it = svcTriples.find(id_);
			if(it!=svcTriples.end())
			{
				if("start"==div_list.at(1)){
					pyfree::svc_control(it->second.svc_name,2);
				}else if("stop"==div_list.at(1)){
					pyfree::svc_control(it->second.svc_name,1);
				}else{
					pyfree::svc_control(it->second.svc_name,0);
				}
				
			}
		}
	}
	return doResponse(req, res);
}

// POST 方式且满足：
// Content-Type: multipart/form-data; boundary=xxx
bool http_servlet::doUpload(acl::HttpServletRequest& req, acl::HttpServletResponse& res)
{
	// 先获得 Content-Type 对应的 http_ctype 对象
	acl::http_mime* mime = req.getHttpMime();
	if (mime == NULL)
	{
		logger_error("http_mime null");
		return false;
	}

	// 获得数据体的长度
	long long int len = req.getContentLength();
	if (len <= 0)
	{
		logger_error("body empty");
		return false;
	}
	Print_NOTICE("ContentLength:%lld\n",len);
	// 获得输入流
	acl::istream& in = req.getInputStream();
	char  buf[8192];
	int   ret;
	bool  finish = false;

	const char* filepath = "./var/mime_file";
	acl::ofstream out;
	out.open_write(filepath);

	// 设置原始文件存入路径
	mime->set_saved_path(filepath);

	size_t k;

	// 读取 HTTP 客户端请求数据
	while (len > 0)
	{
		k = (size_t) len > sizeof(buf)
			? sizeof(buf) : (size_t) len;
		ret = in.read(buf, k, false);
		if (ret == -1)
		{
			logger_error("read POST data error");
			return false;
		}
		out.write(buf, ret);

		len -= ret;

		// 将读得到的数据输入至解析器进行解析
		if (!finish && mime->update(buf, ret) == true)
			finish = true;
	}
	out.close();

	if (len != 0 || finish == false)
		logger_warn("not read all data from client");

	acl::string path;
	// 遍历所有的 MIME 结点，找出其中为文件结点的部分进行转储
	const std::list<acl::http_mime_node*>& nodes = mime->get_nodes();
	std::list<acl::http_mime_node*>::const_iterator cit = nodes.begin();
	for (; cit != nodes.end(); ++cit)
	{
		const char* name = (*cit)->get_name();
		if (name == NULL)
			continue;
		// Print_NOTICE("name:%s\n",name);
		acl::http_mime_t mime_type = (*cit)->get_mime_type();
		if (mime_type == acl::HTTP_MIME_FILE)
		{
			const char* filename = (*cit)->get_filename();
			if (filename == NULL)
			{
				logger("filename null");
				continue;
			}
			// 有的浏览器（如IE）上传文件时会带着文件路径，所以
			// 需要先将路径去掉
			filename = acl_safe_basename(filename);
			// Print_NOTICE("filename:%s\n",filename);
#ifdef WIN32
			std::string file_ = pyfree::UTF_82ASCII(std::string(filename));
			path.format("%s\\%s", name,file_.c_str());
#else
			path.format("%s/%s", name,filename);
#endif
			Print_NOTICE("filepath:%s\n",path.c_str());
			(void) (*cit)->save(path.c_str());
		}
	}
	return doResponse(req, res);
}